/*****************************************************************
 *        File Name : regAHB_monitor.sv
 *           File description :
 *        Author : tanxiao
 *        Date : 2013.6.25
 *        History : 2013.6.25            import           tanxiao
 *****************************************************************
*/




class regAHB_monitor extends uvm_monitor  ;

   virtual AHB_IF   regAHB_vif     ;

   `uvm_component_utils(regAHB_monitor)

   //Constructor
   function new(string name, uvm_component parent);
       super.new(name,parent);
   endfunction : new

   extern virtual function void build_phase(uvm_phase phase);
   extern virtual task run_phase(uvm_phase phase);
   extern virtual task hacc_cmd_reg();



endclass :regAHB_monitor



function void regAHB_monitor::build_phase(uvm_phase phase);

     if(!uvm_config_db#(virtual AHB_IF)::get(this, "", "regAHB_vif", regAHB_vif))
        `uvm_fatal("NOVIF", {"virtual interface must be set for: ", get_full_name(), ".regAHB_vif "}) 

endfunction : build_phase



task regAHB_monitor::run_phase(uvm_phase phase);   

    hacc_cmd_reg();

endtask : run_phase


task regAHB_monitor::hacc_cmd_reg();

    //strobe the ahb bus imformation
   logic [31:0]   reg_addr      ;
   logic [31:0]   reg_data      ;

   //hacc work mode 0:hacc 1:evt_log
   logic          hacc_mode     ;

   //aes key
   logic          aes_key0      ;
   logic          aes_key1      ;
   logic          aes_key2      ;
   logic          aes_key3      ;
   logic          aes_key4      ;
   logic          aes_key5      ;
   logic          aes_key6      ;
   logic          aes_key7      ;

   //Event log int mask
   logic          evt_int_mask  ;

   //HACC int mask
   logic          hacc_int_mask ;

   //AES key width 0:128bit  1:256bit
   logic          key_width     ;

   //aes mode 00:nop 01:enc 10:dec 11:nop
   logic [1:0]    aes_mode      ;

   //hacc enable 
   logic          hacc_en       ;

   //source address 
   logic [31:0]   src_addr      ;

   //destination address  
   logic [31:0]   dest_addr     ;

   //hacc cmd inter frame gap
   logic [5:0]    cmd_ifg       ;

   //hacc cmd valid
   logic          cmd_val       ;

   //hacc cmd valid      
   logic [15:0]   cmd_len       ;

   //event elen
   logic [15:0]   evt_tlen      ;

   //event log source 00: sata 01:nfc
   logic [1:0]    src_en        ;

   //event mode 0 0:once  1:loop
   logic          evt_mode      ;

   //event log mode enable 
   logic          evt_en        ;

   //NL timer config
   logic [4:0]    timer_unit    ; 
   logic [4:0]    timer_punit   ; 

   // event destination address 
   logic [31:0]   evt_addr      ;

   //event log info
   logic [17:0]   evt_log       ;

   //sw event valid
   logic          evt_val       ;


   forever begin
     @(posedge regAHB_vif.HCLK iff regAHB_vif.HSELx === 1'b1);

     if(regAHB_vif.HTRANS == 2'b10 && regAHB_vif.HWRITE == 1'b1)begin
          reg_addr = regAHB_vif.HADDR  ;

          @(posedge regAHB_vif.HCLK);
          reg_data = regAHB_vif.HWDATA ;

          //Global config
          if(reg_addr == `HACC_TOP_CFG) begin
             `uvm_info(get_type_name(), $psprintf("Configuration Register : HACC_TOP_CFG, addr = 32'h%h, data = 32'h%h", reg_addr, reg_data), UVM_HIGH) 

             hacc_mode = reg_data[0];
             if(hacc_mode == 1'b0) begin
                `uvm_info(get_type_name(), $psprintf("hacc working in Hardware Accelerator mode"), UVM_HIGH) 
             end
             else begin
                `uvm_info(get_type_name(), $psprintf("hacc working in Event Log mode"), UVM_HIGH) 
             end

             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "hacc_mode", hacc_mode);

             evt_int_mask = reg_data[9];
             if(evt_int_mask == 1'b0) begin
                `uvm_info(get_type_name(), $psprintf("Event Log interrupt mask on"), UVM_MEDIUM) 
             end
             else begin
                `uvm_info(get_type_name(), $psprintf("Event Log interrupt mask off"), UVM_MEDIUM) 
             end

             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "evt_int_mask", evt_int_mask);

             hacc_int_mask = reg_data[5] ;
             if(hacc_int_mask == 1'b0) begin
                `uvm_info(get_type_name(), $psprintf("Hardware Accelerator interrupt mask on"), UVM_MEDIUM) 
             end
             else begin
                `uvm_info(get_type_name(), $psprintf("Hardware Accelerator interrupt mask off"), UVM_MEDIUM) 
             end
             
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "evt_int_mask", hacc_int_mask);
          end
                 
          else if(reg_addr == `HACC_HW_ACC_CFG) begin        
             `uvm_info(get_type_name(), $psprintf("Configuration Register : HACC_HW_ACC_CFG, addr = 32'h%h, data = 32'h%h", reg_addr, reg_data), UVM_HIGH) 

             key_width = reg_data[8]   ;
             if(key_width == 1'b0) begin
                `uvm_info(get_type_name(), $psprintf("AES key width is 128bit"), UVM_HIGH) 
             end
             else begin
                `uvm_info(get_type_name(), $psprintf("AES key width is 256bit"), UVM_HIGH) 
             end

             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "key_width", key_width);

             aes_mode = reg_data[5:4] ;
             if(aes_mode == 2'b01) begin
                `uvm_info(get_type_name(), $psprintf("AES mode is Encription"), UVM_HIGH) 
             end
             else if(aes_mode == 2'b10) begin
                `uvm_info(get_type_name(), $psprintf("AES mode is Decryption"), UVM_HIGH) 
             end

             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "aes_mode", aes_mode);


             hacc_en = reg_data[0] ;
             if(hacc_en == 1'b0) begin
                `uvm_info(get_type_name(), $psprintf("Hardware Accelerator is Disable "), UVM_HIGH) 
             end
             else begin
                `uvm_info(get_type_name(), $psprintf("Hardware Accelerator is Enable "), UVM_HIGH) 
             end

             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "hacc_en", hacc_en);
          end


          else if(reg_addr == `HACC_DMA_SRC_ADDR) begin
             `uvm_info(get_type_name(), $psprintf("Configuration Register : HACC_DMA_SRC_ADDR, addr = 32'h%h, data = 32'h%h", reg_addr, reg_data), UVM_HIGH) 
   
             src_addr = reg_data   ;  
             `uvm_info(get_type_name(), $psprintf("HACC source data head address : 32'h%h", src_addr), UVM_HIGH) 
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "src_addr", src_addr);
          end

          
          else if(reg_addr == `HACC_DMA_DEST_ADDR) begin
             `uvm_info(get_type_name(), $psprintf("Configuration Register : HACC_DMA_DEST_ADDR, addr = 32'h%h, data = 32'h%h", reg_addr, reg_data), UVM_HIGH) 
   
             src_addr = reg_data   ;  
             `uvm_info(get_type_name(), $psprintf("HACC destination data head address : 32'h%h", dest_addr), UVM_HIGH) 
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "src_addr", dest_addr);
          end


          else if(reg_addr == `HACC_CMD_REG) begin
             `uvm_info(get_type_name(), $psprintf("Configuration Register : HACC_CMD_REG, addr = 32'h%h, data = 32'h%h", reg_addr, reg_data), UVM_HIGH) 

             cmd_ifg = reg_data[29:24] ;
             `uvm_info(get_type_name(), $psprintf("HACC CMD inter frame gap : 32'h%h", cmd_ifg), UVM_HIGH) 
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "cmd_ifg", cmd_ifg);

             cmd_val = reg_data[20] ;
             if(cmd_val == 1'b0) begin
                `uvm_info(get_type_name(), $psprintf("Command Data log is invalid"), UVM_HIGH) 
             end
             else begin
                `uvm_info(get_type_name(), $psprintf("Command Data log is valid"), UVM_HIGH) 
                //when hacc cmd is valid , to transfer a sign to ahb master monitor that a new command coming
                -> hacc_cmd_head;
             end
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "cmd_val", cmd_val);

             cmd_len = reg_data[15:0];
             `uvm_info(get_type_name(), $psprintf("Command Data length : 32'h%h", cmd_len), UVM_HIGH) 
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "cmd_len", cmd_len);
          end


          else if(reg_addr == `HACC_AES_KEY0) begin
             `uvm_info(get_type_name(), $psprintf("Configuration Register : HACC_AES_KEY0, addr = 32'h%h, data = 32'h%h", reg_addr, reg_data), UVM_HIGH) 

             aes_key0 = reg_data ;
             `uvm_info(get_type_name(), $psprintf("HACC AES KEY0: 32'h%h", aes_key0), UVM_HIGH) 
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "aes_key0", aes_key0);
          end
             

          else if(reg_addr == `HACC_AES_KEY1) begin
             `uvm_info(get_type_name(), $psprintf("Configuration Register : HACC_AES_KEY1, addr = 32'h%h, data = 32'h%h", reg_addr, reg_data), UVM_HIGH) 

             aes_key1 = reg_data ;
             `uvm_info(get_type_name(), $psprintf("HACC AES KEY1: 32'h%h", aes_key1), UVM_HIGH) 
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "aes_key1", aes_key1);
          end
             
             
          else if(reg_addr == `HACC_AES_KEY2) begin
             `uvm_info(get_type_name(), $psprintf("Configuration Register : HACC_AES_KEY2, addr = 32'h%h, data = 32'h%h", reg_addr, reg_data), UVM_HIGH) 

             aes_key2 = reg_data ;
             `uvm_info(get_type_name(), $psprintf("HACC AES KEY2: 32'h%h", aes_key1), UVM_HIGH) 
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "aes_key2", aes_key2);
          end


          else if(reg_addr == `HACC_AES_KEY3) begin
             `uvm_info(get_type_name(), $psprintf("Configuration Register : HACC_AES_KEY3, addr = 32'h%h, data = 32'h%h", reg_addr, reg_data), UVM_HIGH) 

             aes_key3 = reg_data ;
             `uvm_info(get_type_name(), $psprintf("HACC AES KEY3: 32'h%h", aes_key3), UVM_HIGH) 
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "aes_key3", aes_key3);
          end


          else if(reg_addr == `HACC_AES_KEY4) begin
             `uvm_info(get_type_name(), $psprintf("Configuration Register : HACC_AES_KEY4, addr = 32'h%h, data = 32'h%h", reg_addr, reg_data), UVM_HIGH) 

             aes_key4 = reg_data ;
             `uvm_info(get_type_name(), $psprintf("HACC AES KEY4: 32'h%h", aes_key4), UVM_HIGH) 
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "aes_key4", aes_key4);
          end


          else if(reg_addr == `HACC_AES_KEY5) begin
             `uvm_info(get_type_name(), $psprintf("Configuration Register : HACC_AES_KEY5, addr = 32'h%h, data = 32'h%h", reg_addr, reg_data), UVM_HIGH) 

             aes_key5 = reg_data ;
             `uvm_info(get_type_name(), $psprintf("HACC AES KEY5: 32'h%h", aes_key5), UVM_HIGH) 
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "aes_key5", aes_key5);
          end


          else if(reg_addr == `HACC_AES_KEY6) begin
             `uvm_info(get_type_name(), $psprintf("Configuration Register : HACC_AES_KEY6, addr = 32'h%h, data = 32'h%h", reg_addr, reg_data), UVM_HIGH) 

             aes_key6 = reg_data ;
             `uvm_info(get_type_name(), $psprintf("HACC AES KEY6: 32'h%h", aes_key6), UVM_HIGH) 
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "aes_key6", aes_key6);
          end


          else if(reg_addr == `HACC_AES_KEY7) begin
             `uvm_info(get_type_name(), $psprintf("Configuration Register : HACC_AES_KEY7, addr = 32'h%h, data = 32'h%h", reg_addr, reg_data), UVM_HIGH) 

             aes_key7 = reg_data ;
             `uvm_info(get_type_name(), $psprintf("HACC AES KEY7: 32'h%h", aes_key7), UVM_HIGH) 
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "aes_key1", aes_key7);
          end


          else if(reg_addr == `HACC_EVENT_CFG) begin
             `uvm_info(get_type_name(), $psprintf("Configuration Register : HACC_EVENT_CFG, addr = 32'h%h, data = 32'h%h", reg_addr, reg_data), UVM_HIGH)
          
             evt_tlen = reg_data[31:16] ;
             `uvm_info(get_type_name(), $psprintf("Event Log RAM space : 32'h%h", evt_tlen), UVM_HIGH) 
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "evt_tlen", evt_tlen);
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.evt_log_agent0.evt_mon", "evt_tlen", evt_tlen);


             src_en = reg_data[9:8] ;
             if(src_en[0] == 1'b1) begin
                `uvm_info(get_type_name(), $psprintf("Event Log from SATA Enable "), UVM_HIGH) 
             end
             else if(src_en[1] == 1'b1) begin
                `uvm_info(get_type_name(), $psprintf("Event Log from NFC Enable "), UVM_HIGH) 
             end

             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "src_en", src_en);
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.evt_log_agent0.evt_mon", "src_en", src_en);
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.evt_log_agent0.evt_mon", "src_en", src_en);

             evt_mode = reg_data[4]  ;
             if(evt_mode == 1'b0) begin
                `uvm_info(get_type_name(), $psprintf("Event Log mode is once "), UVM_HIGH) 
             end
             else begin
                `uvm_info(get_type_name(), $psprintf("Event Log mode is loop "), UVM_HIGH) 
             end

             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "evt_mode", evt_mode);
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.evt_log_agent0.evt_mon", "evt_mode", evt_mode);

             evt_en = reg_data[0] ;
             if(evt_en == 1'b0) begin
                `uvm_info(get_type_name(), $psprintf("Event Log mode is Disable "), UVM_HIGH) 
             end
             else begin
                `uvm_info(get_type_name(), $psprintf("Event Log mode is Enable "), UVM_HIGH) 
                -> evt_cmd_head;
             end

             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "evt_en", evt_en);
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.evt_log_agent0.evt_mon", "evt_en", evt_en);
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.evt_log_agent0.evt_mon", "evt_en", evt_en);
          end


          else if(reg_addr == `HACC_NL_TIMER_CFG) begin
             `uvm_info(get_type_name(), $psprintf("Configuration Register : HACC_NL_TIMER_CFG, addr = 32'h%h, data = 32'h%h", reg_addr, reg_data), UVM_HIGH)

             timer_unit = reg_data[7:4] ;
             `uvm_info(get_type_name(), $psprintf("NL Timer Unit : 32'h%h", timer_unit), UVM_MEDIUM) 
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.evt_log_agent0.evt_mon", "timer_unit", timer_unit);

             timer_punit = reg_data[3:0] ;
             `uvm_info(get_type_name(), $psprintf("NL Timer Pre_Unit : 32'h%h", timer_punit), UVM_MEDIUM) 
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.evt_log_agent0.evt_mon", "timer_punit", timer_punit);
          end


          else if(reg_addr == `HACC_EVENT_ADDR) begin
             `uvm_info(get_type_name(), $psprintf("Configuration Register : HACC_EVENT_ADDR, addr = 32'h%h, data = 32'h%h", reg_addr, reg_data), UVM_HIGH)

             evt_addr = reg_data[25:8] ;
             `uvm_info(get_type_name(), $psprintf("Event log info destination address: 32'h%h", evt_addr), UVM_MEDIUM) 
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "evt_addr", evt_addr);
          end

          else if(reg_addr == `HACC_SW_EVENT) begin
             `uvm_info(get_type_name(), $psprintf("Configuration Register : HACC_SW_EVENT, addr = 32'h%h, data = 32'h%h", reg_addr, reg_data), UVM_HIGH)

             evt_log = reg_data[25:8] ;
             `uvm_info(get_type_name(), $psprintf("Software Event log info : 32'h%h", evt_log), UVM_MEDIUM) 
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "evt_log", evt_log);
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.evt_log_agent0.evt_mon", "evt_log", evt_log);


             evt_val = reg_data[0] ;
             if(evt_val == 1'b0) begin 
                 `uvm_info(get_type_name(), $psprintf("Software Event log is invalid %h", evt_val ), UVM_MEDIUM) 
             end
             else begin
                 `uvm_info(get_type_name(), $psprintf("Software Event log is valid %h", evt_val ), UVM_MEDIUM) 

                 //when Software event log is valid. transfer the event monitor a sign
                 ->evt_sw_head ;
             end

             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.ahbm_if_mon", "evt_val", evt_val);
             uvm_config_db#(int)::set(uvm_root::get, "*.hacc_env0.evt_log_agent0.evt_mon", "evt_val", evt_val);
          end
    
    end// HTRANS
 end

endtask : hacc_cmd_reg


